package com.cryptoneedle.center.source.entity.metadata;


import com.bubbles.engine.data.core.entity.BaseEntity;
import com.cryptoneedle.center.source.entity.constraint.SourceConstraintForeign;
import com.cryptoneedle.center.source.entity.constraint.SourceConstraintPrimary;
import com.cryptoneedle.center.source.entity.constraint.SourceConstraintUnique;
import com.cryptoneedle.center.source.entity.constraint.SourceIndexUnique;
import com.cryptoneedle.center.source.entity.enhance.SourceEnhanceDimension;
import com.cryptoneedle.center.source.entity.enhance.SourceEnhanceDorisAnalyzeColumn;
import com.cryptoneedle.center.source.enums.SourceEnabledReason;
import com.cryptoneedle.center.source.key.metadata.SourceColumnKey;
import jakarta.persistence.*;
import lombok.*;
import lombok.experimental.Accessors;
import org.hibernate.annotations.Comment;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>description: 源数据源-列 </p>
 *
 * @author CryptoNeedle
 * @date 2025-06-19
 */
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true, exclude = {"sourceTable", "sourceConstraintPrimaries", "sourceConstraintUniques", "sourceConstraintForeigns", "sourceIndexUniques"})
@ToString(callSuper = true, exclude = {"sourceTable", "sourceConstraintPrimaries", "sourceConstraintUniques", "sourceConstraintForeigns", "sourceIndexUniques"})
@Entity
@EntityListeners(AuditingEntityListener.class)
@Table(schema = "public", name = "source_column")
@IdClass(SourceColumnKey.class)
@Comment("源数据源-列")
public class SourceColumn extends BaseEntity {
    
    @Id
    @Comment("源数据源-目录名称")
    private String sourceCatalogName;
    
    @Comment("源数据源-系统编码")
    private String sourceSystemCode;
    
    @Id
    @Comment("源数据源-数据库名称")
    private String sourceDatabaseName;
    
    @Id
    @Comment("源数据源-表名称")
    private String sourceTableName;
    
    @Id
    @Comment("源数据源-列名称")
    private String sourceColumnName;
    
    @Column(columnDefinition = "TEXT")
    @Comment("源数据源-列评论")
    private String sourceColumnComment;
    
    @Comment("源数据源-人工指定列评论")
    private Boolean sourceColumnCommentManual;
    
    @Comment("源数据源-启用列")
    private Boolean sourceColumnEnabled;
    
    @Enumerated(EnumType.STRING)
    @Comment("源数据源-启用或关闭列原因")
    private SourceEnabledReason sourceColumnEnabledReason;
    
    @Comment("源数据源-数据类型")
    private String sourceDataType;
    
    @Comment("源数据源-数据长度")
    private Long sourceLength;
    
    @Comment("源数据源-数据精度")
    private Long sourcePrecision;
    
    @Comment("源数据源-数据标度")
    private Long sourceScale;
    
    @Comment("源数据源-排序")
    private Long sourcePosition;
    
    @Embedded
    private SourceStatistic sourceStatistic;
    
    @Embedded
    private DorisStatistic dorisStatistic;
    
    @Embedded
    private DetailStatistic detailStatistic;
    
    @Embedded
    private Doris doris;
    
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    @Embeddable
    public static class SourceStatistic {
        
        @Comment("源数据源统计信息-表数据量")
        private Long sourceStatisticRowCount;
        
        @Comment("源数据源统计信息-采样数量")
        private Long sourceStatisticSampleCount;
        
        @Comment("源数据源统计信息-采样空值数量")
        private Long sourceStatisticNullCount;
        
        @Comment("源数据源统计信息-采样不同值数量")
        private Long sourceStatisticDistinctCount;
        
        @Column(precision = 21, scale = 20)
        @Comment("源数据源统计信息-采样数据密度")
        private BigDecimal sourceStatisticDensity;
        
        @Column(columnDefinition = "TEXT")
        @Comment("源数据源统计信息-采样最小值")
        private String sourceStatisticMinValue;
        
        @Column(columnDefinition = "TEXT")
        @Comment("源数据源统计信息-采样最大值")
        private String sourceStatisticMaxValue;
        
        @Column(precision = 30, scale = 20)
        @Comment("源数据源统计信息-列平均字节数")
        private BigDecimal sourceStatisticAvgDataSizeByte;
        
        @Comment("源数据源统计信息-列总数据量")
        private Long sourceStatisticDataSize;
        
        @Comment("源数据源统计信息-统计时间")
        private Date sourceStatisticDatetime;
    }
    
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    @Embeddable
    public static class DorisStatistic {
        
        @Comment("Doris统计信息-表数据量")
        private Long dorisStatisticRowCount;
        
        @Comment("Doris统计信息-采样数量")
        private Long dorisStatisticSampleCount;
        
        @Comment("Doris统计信息-采样空值数量")
        private Long dorisStatisticNullCount;
        
        @Comment("Doris统计信息-采样不同值数量")
        private Long dorisStatisticDistinctCount;
        
        @Column(precision = 21, scale = 20)
        @Comment("Doris统计信息-采样数据密度")
        private BigDecimal dorisStatisticDensity;
        
        @Column(columnDefinition = "TEXT")
        @Comment("Doris统计信息-采样最小值")
        private String dorisStatisticMinValue;
        
        @Column(columnDefinition = "TEXT")
        @Comment("Doris统计信息-采样最大值")
        private String dorisStatisticMaxValue;
        
        @Column(precision = 30, scale = 20)
        @Comment("Doris统计信息-列平均字节数")
        private BigDecimal dorisStatisticAvgDataSizeByte;
        
        @Comment("Doris统计信息-列总数据量")
        private Long dorisStatisticDataSize;
        
        @Comment("Doris统计信息-统计时间")
        private Date dorisStatisticDatetime;
    }
    
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    @Embeddable
    public static class DetailStatistic {
        
        @Comment("详细统计信息-表数据量")
        private Long detailStatisticRowCount;
        
        @Comment("详细统计信息-采样数量")
        private Long detailStatisticSampleCount;
        
        @Comment("详细统计信息-采样空值数量")
        private Long detailStatisticNullCount;
        
        @Comment("详细统计信息-采样不同值数量")
        private Long detailStatisticDistinctCount;
        
        @Column(precision = 21, scale = 20)
        @Comment("详细统计信息-采样数据密度")
        private BigDecimal detailStatisticDensity;
        
        @Column(columnDefinition = "TEXT")
        @Comment("详细统计信息-采样最小值")
        private String detailStatisticMinValue;
        
        @Column(columnDefinition = "TEXT")
        @Comment("详细统计信息-采样最大值")
        private String detailStatisticMaxValue;
        
        @Column(precision = 30, scale = 20)
        @Comment("详细统计信息-列平均字节数")
        private BigDecimal detailStatisticAvgDataSizeByte;
        
        @Comment("详细统计信息-列总数据量")
        private Long detailStatisticDataSize;
        
        @Comment("详细统计信息-统计时间")
        private Date detailStatisticDatetime;
    }
    
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    @Embeddable
    public static class Transform {
        
        @Comment("转换-系统编码")
        private String transformSystemCode;
        
        @Comment("转换-表名称")
        private String transformTableName;
        
        @Comment("转换-列名称")
        private String transformColumnName;
        
        @Column(columnDefinition = "TEXT")
        @Comment("转换-列评论")
        private String transformColumnComment;
        
        @Comment("转换-数据类型")
        private String transformDataType;
        
        @Comment("转换-数据长度")
        private Long transformLength;
        
        @Comment("转换-数据精度")
        private Long transformPrecision;
        
        @Comment("转换-数据标度")
        private Long transformScale;
        
        @Comment("转换-排序")
        private Long transformPosition;
    }
    
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    @Embeddable
    public static class Doris {
        
        @Comment("DORIS-数据库名称")
        private String dorisDatabaseName;
        
        @Comment("DORIS-表名称")
        private String dorisTableName;
        
        @Comment("DORIS-列名称")
        private String dorisColumnName;
    }
    
    /**
     * 关联关系
     */
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumns({@JoinColumn(name = "sourceCatalogName", referencedColumnName = "sourceCatalogName", insertable = false, updatable = false), @JoinColumn(name = "sourceDatabaseName", referencedColumnName = "sourceDatabaseName", insertable = false, updatable = false), @JoinColumn(name = "sourceTableName", referencedColumnName = "sourceTableName", insertable = false, updatable = false)})
    private SourceTable sourceTable;
    
    @OneToMany(mappedBy = "sourceColumn", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceConstraintPrimary> sourceConstraintPrimaries = new ArrayList<>();
    
    @OneToMany(mappedBy = "sourceColumn", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceConstraintUnique> sourceConstraintUniques = new ArrayList<>();
    
    @OneToMany(mappedBy = "sourceColumn", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceConstraintForeign> sourceConstraintForeigns = new ArrayList<>();
    
    @OneToMany(mappedBy = "sourceColumn", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceIndexUnique> sourceIndexUniques = new ArrayList<>();
    
    @OneToMany(mappedBy = "sourceColumn", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceEnhanceDimension> sourceEnhanceDimensions = new ArrayList<>();
    
    @OneToMany(mappedBy = "sourceColumn", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<SourceEnhanceDorisAnalyzeColumn> sourceEnhanceDorisAnalyzeColumns = new ArrayList<>();
    
    
    public SourceColumn addSourceConstraintPrimary(SourceConstraintPrimary sourceConstraintPrimary) {
        this.sourceConstraintPrimaries.add(sourceConstraintPrimary);
        sourceConstraintPrimary.setSourceColumn(this);
        sourceConstraintPrimary.setSourceCatalogName(this.sourceCatalogName);
        sourceConstraintPrimary.setSourceDatabaseName(this.sourceDatabaseName);
        sourceConstraintPrimary.setSourceTableName(this.sourceTableName);
        sourceConstraintPrimary.setSourceColumnName(this.sourceColumnName);
        return this;
    }
    
    public SourceColumn removeSourceConstraintPrimary(SourceConstraintPrimary sourceConstraintPrimary) {
        this.sourceConstraintPrimaries.remove(sourceConstraintPrimary);
        sourceConstraintPrimary.setSourceColumn(null);
        return this;
    }
    
    public SourceColumn addSourceConstraintUnique(SourceConstraintUnique sourceConstraintUnique) {
        this.sourceConstraintUniques.add(sourceConstraintUnique);
        sourceConstraintUnique.setSourceColumn(this);
        sourceConstraintUnique.setSourceCatalogName(this.sourceCatalogName);
        sourceConstraintUnique.setSourceDatabaseName(this.sourceDatabaseName);
        sourceConstraintUnique.setSourceTableName(this.sourceTableName);
        sourceConstraintUnique.setSourceColumnName(this.sourceColumnName);
        return this;
    }
    
    public SourceColumn removeSourceConstraintUnique(SourceConstraintUnique sourceConstraintUnique) {
        this.sourceConstraintUniques.remove(sourceConstraintUnique);
        sourceConstraintUnique.setSourceColumn(null);
        return this;
    }
    
    public SourceColumn addSourceConstraintForeign(SourceConstraintForeign sourceConstraintForeign) {
        this.sourceConstraintForeigns.add(sourceConstraintForeign);
        sourceConstraintForeign.setSourceColumn(this);
        sourceConstraintForeign.setSourceCatalogName(this.sourceCatalogName);
        sourceConstraintForeign.setSourceDatabaseName(this.sourceDatabaseName);
        sourceConstraintForeign.setSourceTableName(this.sourceTableName);
        sourceConstraintForeign.setSourceColumnName(this.sourceColumnName);
        return this;
    }
    
    public SourceColumn removeSourceConstraintForeign(SourceConstraintForeign sourceConstraintForeign) {
        this.sourceConstraintForeigns.remove(sourceConstraintForeign);
        sourceConstraintForeign.setSourceColumn(null);
        return this;
    }
    
    public SourceColumn addSourceIndexUnique(SourceIndexUnique sourceIndexUnique) {
        this.sourceIndexUniques.add(sourceIndexUnique);
        sourceIndexUnique.setSourceColumn(this);
        sourceIndexUnique.setSourceCatalogName(this.sourceCatalogName);
        sourceIndexUnique.setSourceDatabaseName(this.sourceDatabaseName);
        sourceIndexUnique.setSourceTableName(this.sourceTableName);
        sourceIndexUnique.setSourceColumnName(this.sourceColumnName);
        return this;
    }
    
    public SourceColumn removeSourceIndexUnique(SourceIndexUnique sourceIndexUnique) {
        this.sourceIndexUniques.remove(sourceIndexUnique);
        sourceIndexUnique.setSourceColumn(null);
        return this;
    }
    
    public SourceColumn addSourceEnhanceTableDimension(SourceEnhanceDimension sourceEnhanceDimension) {
        this.sourceEnhanceDimensions.add(sourceEnhanceDimension);
        sourceEnhanceDimension.setSourceColumn(this);
        sourceEnhanceDimension.setSourceCatalogName(this.sourceCatalogName);
        sourceEnhanceDimension.setSourceDatabaseName(this.sourceDatabaseName);
        sourceEnhanceDimension.setSourceTableName(this.sourceTableName);
        sourceEnhanceDimension.setSourceColumnName(this.sourceColumnName);
        return this;
    }
    
    public SourceColumn removeSourceEnhanceTableDimension(SourceEnhanceDimension sourceEnhanceDimension) {
        this.sourceEnhanceDimensions.remove(sourceEnhanceDimension);
        sourceEnhanceDimension.setSourceColumn(null);
        return this;
    }
    
    public SourceColumn addSourceEnhanceDorisAnalyzeColumn(SourceEnhanceDorisAnalyzeColumn sourceEnhanceDorisAnalyzeColumn) {
        this.sourceEnhanceDorisAnalyzeColumns.add(sourceEnhanceDorisAnalyzeColumn);
        sourceEnhanceDorisAnalyzeColumn.setSourceColumn(this);
        sourceEnhanceDorisAnalyzeColumn.setSourceSystemCode(this.sourceSystemCode);
        sourceEnhanceDorisAnalyzeColumn.setSourceDatabaseName(this.sourceDatabaseName);
        sourceEnhanceDorisAnalyzeColumn.setSourceTableName(this.sourceTableName);
        sourceEnhanceDorisAnalyzeColumn.setSourceColumnName(this.sourceColumnName);
        return this;
    }
    
    public SourceColumn removeSourceEnhanceDorisAnalyzeColumn(SourceEnhanceDorisAnalyzeColumn sourceEnhanceDorisAnalyzeColumn) {
        this.sourceEnhanceDorisAnalyzeColumns.remove(sourceEnhanceDorisAnalyzeColumn);
        sourceEnhanceDorisAnalyzeColumn.setSourceColumn(null);
        return this;
    }
    
    /**
     * 其他
     */
    
    public SourceColumnKey getKey() {
        return new SourceColumnKey().setSourceCatalogName(this.sourceCatalogName)
                                    .setSourceDatabaseName(this.sourceDatabaseName)
                                    .setSourceTableName(this.sourceTableName)
                                    .setSourceColumnName(this.sourceColumnName);
    }
    
    public String getStringKey() {
        return getKey().toString();
    }
} 